Skip to content

fix(google-discovery): JSON-safe Option encoding for persisted bindings#706

Merged
RhysSullivan merged 7 commits into
RhysSullivan:mainfrom
aryasaatvik:fix/google-discovery-option-encoding
May 11, 2026
Merged

fix(google-discovery): JSON-safe Option encoding for persisted bindings#706
RhysSullivan merged 7 commits into
RhysSullivan:mainfrom
aryasaatvik:fix/google-discovery-option-encoding

Conversation

@aryasaatvik
Copy link
Copy Markdown
Contributor

@aryasaatvik aryasaatvik commented May 8, 2026

Summary

tools.list returns 500 for any persisted google-discovery source:

Expected Option, got {"_id":"Option","_tag":"Some","value":"V1 error format."}
  at ["parameters"][0]["description"]

In Effect v4, Schema.Option(...) is a self-declaration (Type == Encoded == Option). The v4 migration (edd904c8) swapped v3's optionalWith({ as: "Option" }) for it, so encoded values still hold real Option instances. The binding column is JSON-mode, so Drizzle stringifies — Option.toJSON emits {_id, _tag, value}, which the decoder then rejects on read.

Replaced with Schema.OptionFromOptional(...) (the v4 equivalent of v3's optionalWith({as:"Option"}), already used by openapi). Runtime type stays Option<...>, encoded form is JSON-safe.

Migration

Existing rows persisted with the broken shape still fail to decode. Clear them so bindings re-derive:

  • delete + re-add the source from the UI, or
  • DELETE FROM google_discovery_binding WHERE source_id = '<id>'; and refresh.

Test plan

  • typecheck + vitest run packages/plugins/google-discovery (11/11)
  • re-add a google source locally, confirm tools.list returns 200

Schema.Option in Effect v4 is a self-declaration (Type == Encoded == Option),
so encoded values still hold real Option instances. When the binding column
(JSON-mode text) gets JSON.stringify'd, Option.toJSON emits
{_id, _tag, value} -- which decode then rejects on read with
"Expected Option, got {_id:Option,_tag:Some,value:...}", failing tools.list
with a 500.

Replace Schema.Option(...) with Schema.OptionFromOptional(...) -- the v4
equivalent of v3's optionalWith({ as: "Option" }) -- so encoded form is a
JSON-safe absent/present field while the runtime type stays Option<...>.
Matches the pattern already used by openapi.

Existing rows persisted with the broken shape need to be cleared (delete +
re-add the source, or DELETE FROM google_discovery_binding WHERE source_id =
'...') so bindings re-derive with the corrected encoding.
@aryasaatvik aryasaatvik marked this pull request as ready for review May 8, 2026 05:50
aryasaatvik and others added 6 commits May 8, 2026 11:55
…ing bug

Reproduces the broken vs fixed encoding through Effect's own JSON I/O
pipeline (Schema.encodeEffect + Schema.UnknownFromJsonString + platform-node
FileSystem) so the bug class is captured without any JSON.parse/stringify
on our side.
@RhysSullivan RhysSullivan merged commit 745a2ba into RhysSullivan:main May 11, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants